package project

import (
	"encoding/gob"
	"log"
	"net"
	"sync"
	"time"
)

// 客户端Accept
func TcpBacklogClient() {
	// 客户端地址
	adress := "127.0.0.1:8080" //IPv4

	// TCP协议类型
	// adress := "[::1]:8080" //IPv6
	// 建立链接
	// 模拟多客服端
	// 并发客户端请求
	num := 256
	wg := sync.WaitGroup{} //等待组
	wg.Add(num)

	for i := 0; i < num; i++ {
		// 并发请求
		go func(wg *sync.WaitGroup, no int) {
			defer wg.Done()
			conn, err := net.DialTimeout(tcp, adress, time.Second)
			if err != nil {
				log.Println(err)
				return
			}
			// 保证关闭
			defer conn.Close()
			log.Printf("%d: connection is establish ,client addr is %s\n", no, conn.LocalAddr())

		}(&wg, i)
		time.Sleep(30 * time.Millisecond) //30毫秒
	}
	wg.Wait()
}

// 客户端Accept
func TcpClientRW() {
	// 客户端地址
	adress := "127.0.0.1:8080" //IPv4

	//1、建立链接
	conn, err := net.DialTimeout(tcp, adress, time.Second)
	if err != nil {
		log.Println(err)
		return
	}
	// 保证关闭
	defer conn.Close()
	log.Printf("connection is establish ,client addr is %s\n", conn.LocalAddr())

	//2、从客户端接收数据 Read
	buf := make([]byte, 1024)
	rn, err := conn.Read(buf)
	if err != nil {
		log.Println(err)
		return
	}
	log.Printf("receive data from server,data is %s\n", string(buf[:rn]))

	//3、向客户端发送数据 Write
	// 写操作特点 err==nil && wn ==len(data) 判断和写入长度
	wn, err := conn.Write([]byte("send some data from client" + "\n"))
	if err != nil {
		log.Println(err)
	}
	log.Printf("client write len is %d\n", wn)
}

func TcpWriteClient() {
	// 客户端地址
	adress := "127.0.0.1:8080" //IPv4

	//1、建立链接
	conn, err := net.DialTimeout(tcp, adress, time.Second)
	if err != nil {
		log.Println(err)
		return
	}
	// 保证关闭
	defer conn.Close()
	log.Printf("connection is establish ,client addr is %s\n", conn.LocalAddr())
	// select {} //阻塞

	//2、Read
	// 1、阻塞read操作
	// buf := make([]byte, 1024)
	// rn, err := conn.Read(buf)
	// if err != nil {
	// 	log.Println(err)
	// 	return
	// }
	// log.Printf("receive data from server,data is %s\n", string(buf[:rn]))

	// 2、循环读
	conn.SetReadDeadline(time.Now().Add(10 * time.Second)) //设置读超时时间10s
	// read 本身是阻塞的所以直接for即可
	for {
		buf := make([]byte, 15)
		rn, err := conn.Read(buf)
		if err != nil {
			log.Println(err)
			break
		}
		log.Printf("receive data from server,data is %s\n", string(buf[:rn])) //buf切片循环读取
	}

	// //2、从客户端接收数据 Read
	// buf := make([]byte, 1024)
	// rn, err := conn.Read(buf)
	// if err != nil {
	// 	log.Println(err)
	// 	return
	// }
	// log.Printf("receive data from server,data is %s\n", string(buf[:rn]))

	// //3、向客户端发送数据 Write
	// // 写操作特点 err==nil && wn ==len(data) 判断和写入长度
	// wn, err := conn.Write([]byte("send some data from client" + "\n"))
	// if err != nil {
	// 	log.Println(err)
	// }
	// log.Printf("client write len is %d\n", wn)
}

func TcpClientRWConcurrency() {
	// 客户端地址
	adress := "127.0.0.1:8080" //IPv4

	//1、建立链接
	conn, err := net.DialTimeout(tcp, adress, time.Second)
	if err != nil {
		log.Println(err)
		return
	}
	// 保证关闭
	defer conn.Close()
	log.Printf("connection is establish ,client addr is %s\n", conn.LocalAddr())

	wg := sync.WaitGroup{} // 并发计数器
	//并发写
	wg.Add(1)
	go CliWrite(conn, &wg)

	//并发读
	wg.Add(1)
	go CliRead(conn, &wg)

	wg.Wait() //等待所有并发完成

}

func CliWrite(conn net.Conn, wg *sync.WaitGroup) {
	defer wg.Done() //done 计数器递减
	for {
		// 2、向客户端发送数据 Write 写操作
		wn, err := conn.Write([]byte("send some data from client" + "\n"))
		if err != nil {
			log.Println(err)
		}
		log.Printf("client write len is %d\n", wn)
		time.Sleep(5 * time.Second) //半秒钟
	}

}
func CliRead(conn net.Conn, wg *sync.WaitGroup) {
	defer wg.Done() //done 计数器递减
	for {
		// 3、读取客户端数据 Read 读操作
		buf := make([]byte, 1024)
		rn, err := conn.Read(buf)
		if err != nil {
			log.Println(err)
			return
		}
		log.Printf("receive data from server,data is %s\n", string(buf[:rn]))
	}

}

func TcpClientFormat() {
	// 客户端地址
	adress := "127.0.0.1:8080" //IPv4

	//1、建立链接
	conn, err := net.DialTimeout(tcp, adress, time.Second)
	if err != nil {
		log.Println(err)
		return
	}
	// 保证关闭
	defer conn.Close()
	log.Printf("connection is establish ,client addr is %s\n", conn.LocalAddr())

	wg := sync.WaitGroup{} // 并发计数器
	//并发写
	// wg.Add(1)
	// go CliWrite(conn, &wg)

	//接收端
	wg.Add(1)
	go CliReadFormat(conn, &wg)

	wg.Wait() //等待所有并发完成

}
func CliReadFormat(conn net.Conn, wg *sync.WaitGroup) {
	defer wg.Done() //done 计数器递减
	for {
		// 从客户端接收数据
		// 接收数据后,先解码

		// 传递消息类型
		type Message struct {
			ID      uint   `json:"id,omitempty"`
			Code    string `json:"code,omitempty"`
			Content string `json:"content,omitempty"`
		}
		message := Message{}
		// 1、JSON解码
		// decoder := json.NewDecoder(conn)
		// 2、GOB解码
		decoder := gob.NewDecoder(conn)

		//利用解码操作进行解码
		if err := decoder.Decode(&message); err != nil {
			log.Panicln(err)
			continue
		}
		log.Println(message)
	}

}
